/*
 * TextPlainChromosomeGenerator.java
 *
 * Created on 20 de Abril de 2011, 16:56
 *
 */

package intopo.evogame.partnerselection.chromosome;

import intopo.game.Strategy;
import intopo.util.Util;

import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.Scanner;

/**
 *
 * @author <a href="mailto:mariano.pedro@gmail.pt">Pedro Lopes da Silva Mariano</a>
 *
 * @version 1.0 20 de Abril de 2011
 */
public class TextPlainChromosomeGenerator<S extends Strategy<S>>
	implements ChromosomeGenerator<S, Chromosome<S>>
{
	Chromosome[] chromosome;
	int next;
	/**
	 * Creates a new instance of TextPlainChromosomeGenerator
	 */
	public TextPlainChromosomeGenerator (Scanner scanner, Map<String, Constructor<? extends S>> map, boolean defaultGenes)
		throws Exception
	{
		int numberChromosomes = Util.nextIntExt (scanner, "Number of chromosomes");
		int filled = 0;
		chromosome = new Chromosome [numberChromosomes];
		java.util.Arrays.fill (this.chromosome, null);
		System.out.println (numberChromosomes + " chromosomes to fill in the population");
		filled = readFixedPositions (scanner, map, defaultGenes);
		System.out.println ("filled " + filled + " positions in the population");
		filled += readRemaining (scanner, map, defaultGenes);
		System.out.println ("filled " + filled + " positions in the population");
		if (filled != numberChromosomes) {
			throw new Exception ("There are not enough chromosomes");
		}
		next = 0;
	}
	public int size ()
	{
		return this.chromosome.length;
	}
	public Chromosome<S> next ()
	{
		Chromosome<S> result = (Chromosome<S>) this.chromosome [this.next];
		this.next++;
		return result;
	}
	private int readFixedPositions (Scanner scanner, Map<String, Constructor<? extends S>> map, boolean defaultGenes)
		throws Exception
	{
		int numberEntries = Util.nextIntExt (scanner, "Number of entries in fixed positions in the population");
		int filled = 0;
		while (numberEntries > 0) {
			int index = scanner.nextInt ();
			if (this.chromosome [index] == null) {
				this.chromosome [index] = readChromosome (scanner, map, defaultGenes);
				filled++;
			}
			else {
				throw new Exception ("Position " + index + " is already taken");
			}
			numberEntries--;
		}
		return filled;
	}
	
	private int readRemaining (Scanner scanner, Map<String, Constructor<? extends S>> map, boolean defaultGenes)
		throws Exception
	{
		int numberEntries = Util.nextIntExt (scanner, "Number of entries in remaining positions in the population");
		int filled = 0;
		int index = 0;
		while (numberEntries > 0) {
			int howMany = scanner.nextInt ();
			Chromosome<S> c = readChromosome (scanner, map, defaultGenes);
			while (howMany > 0) {
				while (index < this.chromosome.length && this.chromosome [index] != null) {
					index++;
				}
				if (index == this.chromosome.length) {
					throw new Exception ("Config file has too many chromosomes specified");
				}
				this.chromosome [index] = c;
				filled++;
				howMany--;
				index++;
			}
			numberEntries--;
		}
		return filled;
	}
	private Chromosome<S> readChromosome (Scanner scanner, Map<String, Constructor<? extends S>> map, boolean defaultGenes)
		throws Exception
	{
		if (!defaultGenes) {
			int poolSize = scanner.nextInt ();
			float utilityThreshold = scanner.nextFloat ();
			float delta = scanner.nextFloat ();
			byte bitsPerProbability = scanner.nextByte ();
			return new Chromosome<S> (readStrategy (scanner, map), poolSize, utilityThreshold, delta, bitsPerProbability);
		}
		else {
			return new Chromosome<S> (readStrategy (scanner, map));
		}
	}
	private S readStrategy (Scanner scanner, Map<String, Constructor<? extends S>> map)
		throws Exception
	{
		String word = scanner.next ();
		Constructor<? extends S> c;
		if (map.containsKey (word)) {
			c = map.get (word);
			try {
				return c.newInstance (scanner);
			}
			catch (InstantiationException e) {
				throw new Exception ("Error instanciating an object");
			}
		}
		else {
			throw new Exception ("Unkown tag " + word);
		}
	}
}
